package com.beimi.game.player;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Stack;

import com.beimi.game.common.HuInfo;
import com.beimi.game.common.TingPaiInfo;
import com.beimi.game.module.GameCardModule;
import com.next.core.util.StatMap;

public class PlayerCardModule {
	private Stack<Integer> holds;
	private boolean canPeng;
	private boolean canGang;
	private StatMap<Integer> countMap;
	private int que;
	private boolean canHu;
	private Map<Integer, TingPaiInfo> tingMap;
	private List<Integer> gangPai;
	private int lastFangGangSeat;
	private boolean hued;
	private int guoHuFan;

	private List<Integer> diangangs;
	private List<Integer> wangangs;
	private List<Integer> angangs;
	
	private List<Integer> pengs;
	
	private List<HuInfo> huInfo;

	public PlayerCardModule() {
		holds = new Stack<>();
		countMap = new StatMap<>();
		tingMap = new HashMap<>();
		gangPai = new ArrayList<>();
		diangangs = new ArrayList<>();
		wangangs = new ArrayList<>();
		angangs = new ArrayList<>();
		pengs = new ArrayList<>();
	}

	public void addMajong(int card) {
		holds.add(card);

		countMap.incr(card);
	}

	public List<Integer> getHolds() {
		return holds;
	}

	public void checkCanTingPai() {
		tingMap.clear();

		// 检查手上的牌是不是已打缺，如果未打缺，则不进行判定
		for (int i = 0; i < holds.size(); ++i) {
			int pai = holds.get(i);
			if (getMJType(pai) == que) {
				return;
			}
		}

		// 检查是否是七对 前提是没有碰，也没有杠 ，即手上拥有13张牌
		if (holds.size() == 13) {
			// 有5对牌
			// boolean hu = false;
			int danPai = -1;
			int pairCount = 0;
			for (int k : countMap.keySet()) {
				int c = countMap.get(k);
				if (c == 2 || c == 3) {
					pairCount++;
				} else if (c == 4) {
					pairCount += 2;
				}

				if (c == 1 || c == 3) {
					// 如果已经有单牌了，表示不止一张单牌，并没有下叫。直接闪
					if (danPai >= 0) {
						break;
					}
					danPai = k;
				}
			}

			// 检查是否有6对 并且单牌是不是目标牌
			if (pairCount == 6) {
				// 七对只能和一张，就是手上那张单牌
				// 七对的番数＝ 2番+N个4个牌（即龙七对）
				TingPaiInfo info = new TingPaiInfo();
				info.setFan(2);
				info.setPattern("7pairs");
				tingMap.put(danPai, info);
				// 如果是，则直接返回咯
			}
		}

		// 检查是否是对对胡 由于四川麻将没有吃，所以只需要检查手上的牌
		// 对对胡叫牌有两种情况
		// 1、N坎 + 1张单牌
		// 2、N-1坎 + 两对牌
		int singleCount = 0;
		int colCount = 0;
		int pairCount = 0;
		List<Integer> arr = new ArrayList<>();
		for (int k : countMap.keySet()) {
			int c = countMap.get(k);
			if (c == 1) {
				singleCount++;
				arr.add(k);
			} else if (c == 2) {
				pairCount++;
				arr.add(k);
			} else if (c == 3) {
				colCount++;
			} else if (c == 4) {
				// 手上有4个一样的牌，在四川麻将中是和不了对对胡的 随便加点东西
				singleCount++;
				pairCount += 2;
			}
		}

		if ((pairCount == 2 && singleCount == 0) || (pairCount == 0 && singleCount == 1)) {
			for (int i = 0; i < arr.size(); ++i) {
				// 对对胡1番
				int p = arr.get(i);
				if (!tingMap.containsKey(p)) {
					TingPaiInfo info = new TingPaiInfo();
					info.setFan(1);
					info.setPattern("duidui");
					tingMap.put(p, info);
				}
			}
		}

		// console.log(seatData.holds);
		// console.log(seatData.countMap);
		// console.log("singleCount:" + singleCount + ",colCount:" + colCount +
		// ",pairCount:" + pairCount);
		// 检查是不是平胡
		if (que != 0) {
			checkTingPai(0, 9);
		}

		if (que != 1) {
			checkTingPai(9, 18);
		}

		if (que != 2) {
			checkTingPai(18, 27);
		}
	}

	private void checkTingPai(int begin, int end) {
		for (int i = begin; i < end; ++i) {
			// 如果这牌已经在和了，就不用检查了
			// 将牌加入到计数中
			countMap.incr(i);
			holds.add(i);
			// 逐个判定手上的牌
			boolean ret = checkCanHu();
			if (ret) {
				TingPaiInfo info = new TingPaiInfo();
				info.setFan(0);
				info.setPattern("normal");
				tingMap.put(i, info);
			}

			// 搞完以后，撤消刚刚加的牌
			countMap.desc(i);
			holds.pop();
		}
	}

	private boolean checkCanHu() {
		for (int k : countMap.keySet()) {
			int c = countMap.get(k);
			if (c < 2) {
				continue;
			}
			// 如果当前牌大于等于２，则将它选为将牌
			countMap.desc(k);
			countMap.desc(k);
			// 逐个判定剩下的牌是否满足 ３Ｎ规则,一个牌会有以下几种情况
			// 1、0张，则不做任何处理
			// 2、2张，则只可能是与其它牌形成匹配关系
			// 3、3张，则可能是单张形成 A-2,A-1,A A-1,A,A+1 A,A+1,A+2，也可能是直接成为一坎
			// 4、4张，则只可能是一坎+单张
			// kanzi = [];
			boolean ret = checkSingle();
			countMap.incr(k);
			countMap.incr(k);

			if (ret) {
				// kanzi.push(k);
				// kanzi.push(k);
				return true;
			}
		}
		return isCanHu();
	}

	private boolean checkSingle() {
		// console.log(d);
		int selected = -1;
		int c = 0;
		for (int i = 0; i < holds.size(); ++i) {
			int pai = holds.get(i);
			c = countMap.get(pai);
			if (c != 0) {
				selected = pai;
				break;
			}
		}

		// 如果没有找到剩余牌，则表示匹配成功了
		if (selected == -1) {
			return true;
		}
		// 否则，进行匹配
		if (c == 3) {
			// 直接作为一坎
			countMap.setZore(selected);
			boolean ret = checkSingle();
			// 立即恢复对数据的修改
			countMap.set(selected, c);
			if (ret == true) {
				return true;
			}
		} else if (c == 4) {
			// 直接作为一坎
			countMap.set(selected, 1);
			boolean ret = checkSingle();
			// 立即恢复对数据的修改
			countMap.set(selected, c);

			// 如果作为一坎能够把牌匹配完，直接返回TRUE。
			if (ret == true) {
				return true;
			}
		}

		// 按单牌处理
		return matchSingle(selected);
	}

	private boolean matchSingle(int selected) {
		// 分开匹配 A-2,A-1,A
		boolean matched = true;
		int v = selected % 9;
		if (v < 2) {
			matched = false;
		} else {
			for (int i = 0; i < 3; ++i) {
				int t = selected - 2 + i;
				int cc = countMap.get(t);
				if (cc == 0) {
					matched = false;
					break;
				}
			}
		}
		// 匹配成功，扣除相应数值
		if (matched) {
			// console.log("A-2,A-1,A" + selected);
			countMap.desc(selected - 2);
			countMap.desc(selected - 1);
			countMap.desc(selected);
			boolean ret = checkSingle();
			countMap.incr(selected - 2);
			countMap.incr(selected - 1);
			countMap.incr(selected);
			if (ret == true) {
				return true;
			}
		}

		// 分开匹配 A-1,A,A + 1
		matched = true;
		if (v < 1 || v > 8) {
			matched = false;
		} else {
			for (int i = 0; i < 3; ++i) {
				int t = selected - 1 + i;
				int cc = countMap.get(t);
				if (cc == 0) {
					matched = false;
					break;
				}
			}
		}

		// 匹配成功，扣除相应数值
		if (matched) {
			// console.log("A-1,A,A + 1" + selected);
			countMap.desc(selected - 1);
			countMap.desc(selected);
			countMap.desc(selected + 1);
			boolean ret = checkSingle();
			countMap.incr(selected - 1);
			countMap.incr(selected);
			countMap.incr(selected + 1);
			if (ret == true) {
				return true;
			}
		}

		// 分开匹配 A,A+1,A + 2
		matched = true;
		if (v > 6) {
			matched = false;
		} else {
			for (int i = 0; i < 3; ++i) {
				int t = selected + i;
				int cc = countMap.get(t);
				if (cc == 0) {
					matched = false;
					break;
				}
			}
		}

		// 匹配成功，扣除相应数值
		if (matched) {
			countMap.desc(selected);
			countMap.desc(selected + 1);
			countMap.desc(selected + 2);
			boolean ret = checkSingle();
			countMap.incr(selected);
			countMap.incr(selected + 1);
			countMap.incr(selected + 2);
			if (ret == true) {
				return true;
			}
		}
		return false;
	}

	public void checkCanHu(int targetPai) {
		// TODO: lastHuPaiSeat
		// game.lastHuPaiSeat = -1;
		if (getMJType(targetPai) == que) {
			return;
		}
		setCanHu(false);
		for (int k : tingMap.keySet()) {
			if (targetPai == k) {
				setCanHu(true);
			}
		}
	}

	private int getMJType(int id) {
		if (id >= 0 && id < 9) {
			// 筒
			return 0;
		} else if (id >= 9 && id < 18) {
			// 条
			return 1;
		} else if (id >= 18 && id < 27) {
			// 万
			return 2;
		}
		return -1;
	}

	public boolean remove(int pai) {
		if (holds.remove((Object) pai)) {
			countMap.desc(pai);
			return true;
		}

		return false;
	}

	public Map<Integer, TingPaiInfo> getTingMap() {
		return tingMap;
	}

	public void checCanPeng(int pai) {
		if (getMJType(pai) == que) {
			return;
		}
		int count = countMap.get(pai);
		if (count >= 2) {
			setCanPeng(true);
		}
	}

	public void checkCanDianGang(int pai) {
		// TODO: 检测麻将数量够不够
		// if (game.mahjongs.length <= game.currentIndex) {
		// return;
		// }
		if (getMJType(pai) == que) {
			return;
		}
		int count = countMap.get(pai);
		if (count >= 3) {
			setCanGang(true);
			gangPai.add(pai);
			return;
		}
	}

	public boolean isCanPeng() {
		return canPeng;
	}

	public void setCanPeng(boolean canPeng) {
		this.canPeng = canPeng;
	}

	public boolean isCanGang() {
		return canGang;
	}

	public void setCanGang(boolean canGang) {
		this.canGang = canGang;
	}

	public StatMap<Integer> getCountMap() {
		return countMap;
	}

	public void clearOptions() {
		canPeng = false;
		canGang = false;
		gangPai.clear();
		setCanHu(false);
		setLastFangGangSeat(-1);
	}

	public boolean isCanHu() {
		return canHu;
	}

	public void setCanHu(boolean canHu) {
		this.canHu = canHu;
	}

	public boolean isHued() {
		return hued;
	}

	public void setHued(boolean hued) {
		this.hued = hued;
	}

	public void mopai(GameCardModule cardModule) {
		int pai = cardModule.pop();
		addMajong(pai);
	}

	public int getLastFangGangSeat() {
		return lastFangGangSeat;
	}

	public void setLastFangGangSeat(int lastFangGangSeat) {
		this.lastFangGangSeat = lastFangGangSeat;
	}

	public int getGuoHuFan() {
		return guoHuFan;
	}

	public void setGuoHuFan(int guoHuFan) {
		this.guoHuFan = guoHuFan;
	}

	public boolean hasOperation() {
		return isCanGang() || isCanHu() || isCanPeng();
	}

	public void beginMoPai() {

	}

	public int getNumOfGen() {
		 int numOfGangs = diangangs.size() + wangangs.size() + angangs.size();
		    for(int k = 0; k < pengs.size(); ++k){
		        int pai = pengs.get(k);
		        if(countMap.get(pai) == 1){
		            numOfGangs++;
		        }
		    }
		    for(int k : countMap.keySet()){
		        if(countMap.get(k) == 4){
		            numOfGangs++;
		        }
		    }
		    return numOfGangs;
	}

	public List<HuInfo> getHuInfo() {
		return huInfo;
	}

	public void setHuInfo(List<HuInfo> huInfo) {
		this.huInfo = huInfo;
	}
	
	public List<Integer> getPengs() {
		return pengs;
	}

	public void randomPop() {
		
	}
}
